# ------------------------------------------------------------
# readListGrammar.py
# 
# Chase Miller
# CS 550 - Assignment 1.2a Grammar
#
# Largely inspired from examples from http://www.dabeaz.com/ply/ply.html#ply_nn2
#
# ------------------------------------------------------------

import ply.yacc as yacc
import __builtin__ as builtin
import sys, os

# Get the token map from the lexer.  This is required.
from readListLex import tokens

class ListElement():
    'Represents a list element' 
    __list = None
    __element = None
    
    def __init__(self, listOrElement):
        '''
        listOrElement of type MyList or int
        '''
        if isinstance(listOrElement, MyList):
            self.__list = listOrElement
        else:
            self.__element = listOrElement
    
    def __str__(self):
        'Print a representation of this object'
        if(self.__list):
            return str(self.__list)
        else:
            return str(self.__element)

class Sequence():
    'Represents a sequence' 
    __listElement = None
    __sequence = None
    
    def __init__(self, listElement, sequence = None, separatorSymbol = ' '):
        '''
        listElement is of type ListElement
        sequence is of type Sequence
        separatorSymbol is a string that represents a list separator
        '''
        self.__listElement = listElement
        self.__sequence = sequence
        self.__separatorSymbol = separatorSymbol
    
    def __str__(self):
        'Print a representation of this object'
        if(self.__sequence):
            return str(self.__listElement) + self.__separatorSymbol + str(self.__sequence)
        else:
            return str(self.__listElement)

class MyList( ) :  
    'Represents a list' 
    __sequence = None
    
    def __init__( self, opening, closing, sequence = None ) :
        'sequence is of type Sequence'
        self.__sequence = sequence
        self.__opening = opening
        self.__closing = closing
    
    def __str__(self):
        'Print a representation of this object'
        if(self.__sequence):
            return str(self.__opening) + str(self.__sequence) + str(self.__closing)
        else:
            return str(self.__opening) + str(self.__closing)

def p_expression_list(p):
    '''list : LPAREN sequence RPAREN 
            | LPAREN RPAREN'''
    if(len(p) == 4):
        myList = MyList(p[1], p[3], p[2])
        p[0] = myList
    else:
        p[0] = MyList(p[1], p[2])
    
def p_expression_sequence(p):
    '''sequence : listelement COMMA sequence 
                | listelement'''
    if(len(p) == 4):
        mySequence = Sequence(p[1], p[3], p[2])
        p[0] = mySequence
    else:
        mySequence = Sequence(p[1])
        p[0] = mySequence

def p_expression_listelement(p):
    '''listelement : list 
                    | NUMBER'''
    if (p[1]): #if p[1] is None, then its a list, so don't add
        listElement = ListElement(p[1])
        p[0] = listElement

# Error rule for syntax errors
def p_error(p):
    print "-error-"
    exit()

if __name__ == '__main__':
    '''The "Main" method'''
    
    if(os.fstat(sys.stdin.fileno()).st_size > 0): #make sure stdin was supplied
        
        contentAsString = ''
        for line in sys.stdin:
            contentAsString += line
                
        # Build the parser
        parser = yacc.yacc()
        
        result = parser.parse(contentAsString)
        
        print result  #now print the internal data structure, a MyList object.  Rely on this object's __str__ method.
    else:
        print 'Usage: please supply stdin'
        exit()